import socket
import struct
import base64
import os
import threading
import time as sys_time
import logging
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from datetime import datetime, time, timedelta
from .models import Pile, Order,GunStatus
from . import csvread
from .utils import vin_to_ascii, decimal_to_hex, decimal_to_little_endian_hex, CP56Time,little_endian_hex_to_dec,update_rates,cost_fee

logger = logging.getLogger('django')
# ================ 协议常量 ================
START_FLAG = 0x68
FRAME_TYPE_LOGIN = 0x01  # 登录
FRAME_TYPE_HEARTBEAT_REPLY = 0x04  # 心跳回复 <-- 新增常量
FRAME_TYPE_BILLING = 0x05  # 计费验证
FRAME_TYPE_BILLING_REQUEST = 0x09  # 计费请求
FRAME_TYPE_BILLING_REQUEST_REPLY = 0x0A  # 计费请求回复
FRAME_TYPE_BILLING_SET = 0x58  # 平台推送计费模型
FRAME_TYPE_BILLING_SET_REPLY = 0x57  # 计费模型设置回复 (新增)
FRAME_TYPE_HEARTBEAT = 0x03  # 心跳包
FRAME_TYPE_STANDBY_DATA = 0x13  # 待机数据
FRAME_TYPE_START_CHARGE = 0xA8  # 平台启动充电
FRAME_TYPE_START_CHARGE_REPLY = 0xA7  # 桩回复启动充电
FRAME_TYPE_CHARGE_HANDSHAKE = 0x15  # 充电握手
FRAME_TYPE_BMS_DATA = 0x25  # 充电过程BMS信息
FRAME_TYPE_ODP_DATA = 0x23  # 充电过程充电机输出
FRAME_TYPE_REALTIME_DATA = 0x13  # 实时监测数据
FRAME_TYPE_STOP_CHARGE = 0x36  # 平台停止充电
FRAME_TYPE_STOP_REPLY = 0x35  # 桩回复停止
FRAME_TYPE_STOP_CHARGE_PILE = 0x19  # 桩停止充电
FRAME_TYPE_STOP_CHARGE_ODP = 0x21  # 充电机停止
FRAME_TYPE_STOP_CHARGE_BMS = 0x1D  # BMS停止
FRAME_TYPE_TRANSACTION_RECORD = 0x3D  # 交易记录

# 密钥处理
key = base64.b64decode("Z8Zpc1H/Suwpzbqr8vvjRg==")
iv = key

# ================ 工具函数 ================
def crc16_modbus(data):
    """CRC16校验"""
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc >>= 1
    return crc.to_bytes(2, 'big')

def aes_encrypt(hex_str):
    """AES加密"""
    plaintext = bytes.fromhex(hex_str)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return cipher.encrypt(pad(plaintext, AES.block_size)).hex()

def aes_decrypt(hex_str):
    """AES解密"""
    ciphertext = bytes.fromhex(hex_str)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(ciphertext), AES.block_size).hex()

class Gun:
    def __init__(self, gun_id, pile):
        self.gun_id = gun_id
        self.pile = pile
        self.device_id = f"{pile.number}{gun_id}"  # 设备ID = 桩号+枪号
        self.charging = False
        self.current_order = ""
        self.stop_charge_time = ""
        self.start_charge_time =  ""
        self.pile_sta = "02"  # 初始状态：空闲  00离线（需要未插枪）   01故障（需要未插枪）   02空闲（需要未插枪）   03充电
        self.pile_on = "01"  # 初始状态：已插枪   00未插枪    01已插枪
        self.csv_lock = threading.Lock()  # 每个枪独立锁
        #self.csv_path = "data.csv"  # CSV文件路径
        base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        self.csv_path = os.path.join(base_dir, 'iot_ykc_simulator', 'data.csv')

        # 最后充电状态
        self.last_bat_soc = 0
        self.last_cha_time = 0
        self.last_cha_ene = 0
        self.cha_ene_end = 0
        self.last_ChaMoney = 0

        # 费率数据
        self.rate_energy_sums = {}
        self.rate_total_cost_sums = {}

        # CSV索引
        self.csv_index = 0
        self.csv_data = []
        self.column_indices = {}
        self.load_csv_data()

        # 费率信息
        self.rate_peak = 0.0
        self.rate_peak_service = 0.0
        self.rate_standard = 0.0
        self.rate_standard_service = 0.0
        self.rate_off_peak = 0.0
        self.rate_off_peak_service = 0.0
        self.rate_valley = 0.0
        self.rate_valley_service = 0.0
        self.rate_peak_all = ""
        self.rate_standard_all = ""
        self.rate_off_peak_all = ""
        self.rate_valley_all = ""
        self.RATE_MAPPING = {}
        self.RATE_PERIODS = []

        try:
            status = GunStatus.objects.get(pile=pile, gun_id=gun_id)
            self.pile_sta = status.status
            self.pile_on = status.plugged_in
        except GunStatus.DoesNotExist:
            # 如果数据库中没有记录，使用默认值
            # 创建新记录时关联桩
            GunStatus.objects.create(
                pile=pile,  # 添加桩关联
                gun_id=gun_id,
                status="02",
                plugged_in="01"
            )

            self.pile_sta = "02"
            self.pile_on = "01"
    def load_csv_data(self):
        """加载CSV数据"""
        try:
            with self.csv_lock:
                self.csv_data, self.column_indices = csvread.load_csv_data(self.csv_path)
                #logger.info(f"枪 {self.gun_id} 加载CSV数据成功，共 {len(self.csv_data)} 行")
        except Exception as e:
            logger.error(f"加载CSV数据失败: {e}")
            self.csv_data = []
            self.column_indices = {}

    def aes_decrypt(self, hex_str):
        """AES解密"""
        ciphertext = bytes.fromhex(hex_str)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        return unpad(cipher.decrypt(ciphertext), AES.block_size).hex()

    def start_charging(self, order_sn):
        """开始充电"""
        self.current_order = order_sn
        self.charging = True
        self.start_charge_time = CP56Time()
        self.pile_sta = "03"  # 充电中
        self.csv_index = 0  # 重置数据索引
        self.real_start_time = datetime.now()

        # 更新数据库状态
        try:
            status = GunStatus.objects.get(pile=self.pile, gun_id=self.gun_id)
            status.status = "03"
            status.plugged_in = "01"
            status.save()
        except GunStatus.DoesNotExist:
            # 如果数据库中没有记录，创建新记录
            GunStatus.objects.create(
                pile=self.pile,
                gun_id=self.gun_id,
                status="03",
                plugged_in="01"
            )

        # 创建订单
        Order.objects.create(
            order_sn=order_sn,
            station=self.pile.station,
            pile=self.pile,
            gun_id=self.gun_id,
            status='charging'
        )
        logger.info(f"枪 {self.gun_id} 启动充电 | 订单: {self.current_order}")

    def stop_charging(self, stop_reason="正常结束"):
        """停止充电"""
        self.charging = False
        self.stop_charge_time = CP56Time()
        self.pile_sta = "02"  # 空闲
        self.real_end_time = datetime.now()

        # 更新数据库状态
        try:
            status = GunStatus.objects.get(pile=self.pile, gun_id=self.gun_id)
            status.status = "02"
            status.save()
        except GunStatus.DoesNotExist:
            GunStatus.objects.create(
                pile=self.pile,
                gun_id=self.gun_id,
                status="02",
                plugged_in="01"  # 默认已插枪
            )

        # 更新订单状态
        try:
            order = Order.objects.get(order_sn=self.current_order)
            order.status = 'completed'
            order.stop_reason = stop_reason
            order.energy = little_endian_hex_to_dec(self.last_cha_ene)/ 10000
            order.total_cost = little_endian_hex_to_dec(self.last_ChaMoney) / 10000
            order.start_time = self.real_start_time
            order.end_time = self.real_end_time
            order.save()
            logger.info(f"枪 {self.gun_id} 停止充电 | 订单: {self.current_order}, 原因: {stop_reason}")
        except Order.DoesNotExist:
            logger.error(f"订单不存在: {self.current_order}")

    def get_charging_data(self):

        """获取充电数据"""
        if self.csv_index >= len(self.csv_data):
            logger.info(f"枪 {self.gun_id} CSV数据结束，准备停止充电")
            self.stop_charging("充电完成")
            return None, None, None, None, None, None
        # 使用锁保护CSV数据访问
        with self.csv_lock:
            if self.csv_index >= len(self.csv_data):
                return None, None, None, None, None, None

            # 读取当前枪的CSV数据
            data_line = self.csv_data[self.csv_index]
            self.csv_index += 1

            # 按列索引获取特定值
            bat_soc = data_line[self.column_indices['BatSOC']]
            cha_ene = data_line[self.column_indices['ChaEne']]
            bat_over_cha_time = data_line[self.column_indices['BatOverChaTime']]
            cha_time = data_line[self.column_indices['ChaTime']]
            logger.info(f"订单号: {self.current_order}, 读取值: BatSOC={bat_soc}%, ChaEne={cha_ene}kWh, "
                  f"BatOverChaTime={bat_over_cha_time}min, ChaTime={cha_time}min")
            # 计算费用（基于共享费率）
            current_time = datetime.now()
            total_cost, rate_energy_sums, _, _, rate_total_cost_sums = cost_fee(
                self.RATE_MAPPING, self.RATE_PERIODS,
                self.real_start_time.strftime("%Y-%m-%d %H:%M:%S"),
                current_time.strftime("%Y-%m-%d %H:%M:%S"),
                cha_ene
            )

            # 更新枪状态
            self.rate_energy_sums = rate_energy_sums
            self.rate_total_cost_sums = rate_total_cost_sums

            self.last_bat_soc = decimal_to_hex(bat_soc, 1)
            gun_cha_time = decimal_to_hex(cha_time, 2)
            gun_bat_over_cha_time = decimal_to_hex(bat_over_cha_time, 2)

            gun_cha_ene_hex = decimal_to_little_endian_hex(cha_ene * 10000)
            self.cha_ene_end = decimal_to_little_endian_hex(cha_ene * 10000, 5)
            gun_ChaMoney = decimal_to_little_endian_hex(total_cost * 10000)

            # 更新最后记录的值
            self.last_ChaMoney = gun_ChaMoney
            self.last_cha_time = gun_cha_time
            self.last_cha_ene = gun_cha_ene_hex

            return (
                self.last_bat_soc,
                gun_cha_time,
                gun_bat_over_cha_time,
                gun_cha_ene_hex,
                gun_ChaMoney
            )

class FrameBuilder:
    def __init__(self, pile):
        self.pile = pile
        self.sequence = 0
        self.lock = threading.Lock()  # 序列号线程锁
        key_str = "Z8Zpc1H/Suwpzbqr8vvjRg=="
        self.key = base64.b64decode(key_str)
        self.iv = self.key

    def aes_encrypt(self, hex_str):
        """AES加密"""
        plaintext = bytes.fromhex(hex_str)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return cipher.encrypt(pad(plaintext, AES.block_size)).hex()

    def build_frame(self, frame_type, encrypted, data_body):
        """通用帧构建"""
        with self.lock:
            header = struct.pack('!HBB', self.sequence, encrypted, frame_type)
            data_part = header + data_body
            frame_head = struct.pack('!BB', START_FLAG, len(data_part))
            full_frame = frame_head + data_part
            crc = crc16_modbus(full_frame[2:])
            self.sequence = (self.sequence + 1) % 65536
            full_frame_bytes = full_frame + crc
            logger.debug(f"构建帧: 类型={frame_type:02X}, 长度={len(full_frame_bytes)}, 序列={self.sequence - 1}")
            return full_frame_bytes

    def build_login(self):
        """桩级登录帧（全桩唯一）"""
        data = (
                "6C784561506B704B4E4B6734356850794B4F564C53446D7061686147457257526F74363363575A4E696F6A50714E344945336643525055736E72326C304368674876784D35464E6968"
                "624553316F444D7345767571513D3D" + self.pile.number + "00" +
                str(self.pile.gun_count).zfill(2) + "01080156312E333000000003000000000000000000000400000000000000"
        )
        data_bytes = bytes.fromhex(data)
        return self.build_frame(FRAME_TYPE_LOGIN, 0x00, data_bytes)

    def build_heartbeat(self, device_id):
        """枪级心跳帧"""
        raw_data = device_id + "00"
        data_bytes = bytes.fromhex(raw_data)
        return self.build_frame(FRAME_TYPE_HEARTBEAT, 0x00, data_bytes)

    def build_billing_request(self):
        """桩级计费请求"""
        encrypted = self.aes_encrypt(self.pile.number)
        return self.build_frame(FRAME_TYPE_BILLING_REQUEST, 0x01, bytes.fromhex(encrypted))

    def build_billing_set_reply(self):
        """桩级计费模型回复"""
        encrypted = self.aes_encrypt(self.pile.number+"01")
        return self.build_frame(FRAME_TYPE_BILLING_SET_REPLY, 0x01, bytes.fromhex(encrypted))
    def build_standby_data(self, device_id, pile_sta, pile_on):
        """枪级待机数据"""
        encrypted = self.aes_encrypt(
            "00000000000000000000000000000000" +
            device_id + pile_sta + "02" + pile_on +
            "000000000000000000000000000000000000000000000000000000000000000000"
        )
        return self.build_frame(FRAME_TYPE_STANDBY_DATA, 0x01, bytes.fromhex(encrypted))

    # 开始充电流程
    def build_start_reply(self, order_sn, device_id):
        """启动响应帧"""
        encrypted = self.aes_encrypt(order_sn + device_id + "0100")
        return self.build_frame(FRAME_TYPE_START_CHARGE_REPLY, 0x01, bytes.fromhex(encrypted))

    def build_charge_handshake(self, order_sn, device_id):
        """充电握手帧"""
        vin = vin_to_ascii(self.pile.vin or "LRW3E7EA5LC025355")
        encrypted = self.aes_encrypt(
            order_sn + device_id + "01010006dc05840d4341544cffffffffffffffffffffffff" + vin + "ffffffffffffffff"
        )
        return self.build_frame(FRAME_TYPE_CHARGE_HANDSHAKE, 0x01, bytes.fromhex(encrypted))

    # 停止充电流程
    def build_stop_reply(self, device_id):
        """停止响应帧"""
        encrypted = self.aes_encrypt(device_id + "0100")
        return self.build_frame(FRAME_TYPE_STOP_REPLY, 0x01, bytes.fromhex(encrypted))

    def build_stop_pile(self, order_sn, device_id, last_bat_soc, last_cha_time, last_cha_ene):
        """桩停止帧"""
        encrypted = self.aes_encrypt(
            order_sn + device_id + last_bat_soc + "920193014d51" + last_cha_time + last_cha_ene + "00000000"
        )
        return self.build_frame(FRAME_TYPE_STOP_CHARGE_PILE, 0x01, bytes.fromhex(encrypted))

    # 充电过程数据
    def build_bms_data(self, order_sn, device_id):
        """BMS数据帧"""
        encrypted = self.aes_encrypt(order_sn + device_id + "004f004d0000d0")
        return self.build_frame(FRAME_TYPE_BMS_DATA, 0x01, bytes.fromhex(encrypted))

    def build_realtime_data(self, order_sn, device_id, bat_soc, cha_time, bat_over_cha_time, cha_ene, ChaMoney):
        """实时数据帧"""
        encrypted = self.aes_encrypt(
            order_sn + device_id + "030201" + "b40d" + "7d00" + "5a0000000000000000" +
            bat_soc + "4f" + cha_time + bat_over_cha_time + cha_ene + "00000000" + ChaMoney + "0000"
        )
        return self.build_frame(FRAME_TYPE_REALTIME_DATA, 0x01, bytes.fromhex(encrypted))

    def build_odp_data(self, order_sn, device_id, bat_soc, bat_over_cha_time, cha_time):
        """充电机数据帧"""
        encrypted = self.aes_encrypt(
            order_sn + device_id + "f50f250b02b00e5a0f0000" + bat_soc + bat_over_cha_time + "b30e360f" + cha_time
        )
        return self.build_frame(FRAME_TYPE_ODP_DATA, 0x01, bytes.fromhex(encrypted))

    # 交易记录
    def build_transaction_record(self, order_sn, device_id, stop_charge_time, start_charge_time,
                                 rate_peak_all, rate_standard_all, rate_off_peak_all, rate_valley_all,
                                 energy_00_hex, cost_00_hex, energy_01_hex, cost_01_hex,
                                 energy_02_hex, cost_02_hex, energy_03_hex, cost_03_hex,
                                 cha_ene_end, last_cha_ene, last_ChaMoney):
        """交易记录帧"""
        vin = vin_to_ascii(self.pile.vin or "LRW3E7EA5LC025355")
        raw_data = (
                order_sn + device_id + start_charge_time + stop_charge_time +
                "62520090240100000000000000000000000000000000000000000000000000000000000000000000b10200" +
                rate_peak_all + energy_00_hex + "00000000" + cost_00_hex +
                rate_standard_all + energy_01_hex + "00000000" + cost_01_hex +
                rate_off_peak_all + energy_02_hex + "00000000" + cost_02_hex +
                rate_valley_all + energy_03_hex + "00000000" + cost_03_hex +
                "0000000000" + cha_ene_end + last_cha_ene + "00000000" + last_ChaMoney +
                vin + "01" + stop_charge_time + "405028420827279362"
        )
        encrypted = self.aes_encrypt(raw_data)
        return self.build_frame(FRAME_TYPE_TRANSACTION_RECORD, 0x01, bytes.fromhex(encrypted))


class PileConnector:
    def __init__(self, pile):
        self.pile = pile
        self.sock = socket.socket()
        self.builder = FrameBuilder(pile)
        self.running = False
        #self.csv_path = "data.csv"
        self.first_heartbeat_reply = False  # 新增：跟踪是否收到第一个心跳回复

        # 初始化多枪实例
        self.guns = {}
        for i in range(1, pile.gun_count + 1):
            gun_id = f"{i:02d}"  # 枪号: 01, 02...
            self.guns[gun_id] = Gun(gun_id, pile)
            logger.info(f"初始化枪 {gun_id} | 设备ID: {self.guns[gun_id].device_id}")

        self.lock = threading.Lock()  # Socket线程锁
        self.billing_received = False  # 跟踪是否已收到费率响应

        self.sync_gun_status_from_db()

    def sync_gun_status_from_db(self):
        """从数据库同步枪状态到内存"""
        try:
            for gun_status in GunStatus.objects.filter(pile=self.pile):
                gun_id = gun_status.gun_id
                if gun_id in self.guns:
                    self.guns[gun_id].pile_sta = gun_status.status
                    self.guns[gun_id].pile_on = gun_status.plugged_in
        except Exception as e:
            logger.error(f"同步枪状态失败: {e}")

    def connect(self):
        """连接服务器（桩级）"""
        if self.pile.logged_in:
            self.pile.logged_in = False
            self.pile.save(update_fields=['logged_in'])
        try:
            self.sock.connect((self.pile.station.host, self.pile.station.port))
            self.sock.settimeout(5.0)  # 设置超时

            # 发送登录帧
            login_frame = self.builder.build_login()
            self.safe_send(login_frame)
            logger.info(f"已发送登录帧：{login_frame.hex()}")
            logger.info(f"桩 {self.pile.number} 登录帧已发送")

            # 启动接收线程
            self.running = True
            threading.Thread(target=self.recv_thread, daemon=True).start()
            # 更新桩状态
            self.pile.logged_in = True
            self.pile.save()
            #sys_time.sleep(1)
            #self.start_charging_process()
            return True
        except Exception as e:
            logger.error(f"桩 {self.pile.number} 连接失败: {e}")
            self.disconnect("连接失败")  # 添加停止原因
            return False

    def disconnect(self, stop_reason="正常断开"):
        """关闭连接"""
        self.running = False

        # 停止所有正在充电的枪
        for gun in self.guns.values():
            if gun.charging:
                gun.stop_charging(stop_reason)  # 传递停止原因

        # 安全关闭套接字
        try:
            # 检查套接字是否可用
            if self.sock and not self.sock._closed:  # 检查套接字状态
                try:
                    # 尝试设置超时，避免在关闭时阻塞
                    self.sock.settimeout(1.0)
                    # 尝试优雅关闭
                    self.sock.shutdown(socket.SHUT_RDWR)
                except OSError as e:
                    # 预期中的错误，可能已经关闭
                    if e.winerror != 10057:  # 如果不是"已关闭的套接字"
                        logger.warning(f"shutdown错误: {e}")
                finally:
                    # 确保关闭套接字
                    self.sock.close()
                    #logger.info(f"关闭套接字: {self.pile.number}")
        except Exception as e:
            logger.error(f"关闭连接错误: {e}")
        finally:
            try:
                # 更新桩状态
                self.pile.logged_in = False
                self.pile.save()
                #logger.info(f"桩 {self.pile.number} 断开连接, 原因: {stop_reason}")
            except Exception as e:
                logger.error(f"更新桩状态失败: {e}")

    def safe_send(self, data):
        """线程安全发送"""
        with self.lock:
            try:
                self.sock.send(data)
                logger.debug(f"发送数据: 长度={len(data)}, 头={data[:2].hex()}")
                return True
            except Exception as e:
                logger.error(f"发送数据失败: {e}")
                return False

    def recv_thread(self):
        """数据接收线程"""
        logger.info(f"桩 {self.pile.number} 接收线程启动")
        while self.running:
            try:
                data = self.sock.recv(1024)
                if not data:
                    logger.warning("连接已关闭")
                    break
                self.process_data(data)
            except socket.timeout:
                continue
            except ConnectionResetError:
                logger.error("连接被服务端强制关闭")
                break
            except Exception as e:
                if self.running:
                    logger.error(f"接收异常: {e}")
                break

        logger.info(f"桩 {self.pile.number} 接收线程退出")
        self.disconnect("接收线程退出")  # 添加停止原因

    def process_data(self, data):
        """处理接收到的原始数据"""
        if len(data) < 6:
            logger.warning("数据长度不足")
            return

        # 提取帧类型
        frame_type = data[5]
        logger.info(f"收到帧类型: 0x{frame_type:02X}")
        #print(f"已收到数据：{data.hex()}")
        logger.info(f"已收到数据: {data.hex()}")

        if frame_type == FRAME_TYPE_HEARTBEAT_REPLY:
            #logger.info(f"桩 {self.pile.number} 收到心跳回复(0x04)")
            if not self.first_heartbeat_reply:
                #logger.info(f"桩 {self.pile.number} 收到第一个心跳回复，准备发送计费请求")
                self.first_heartbeat_reply = True
                # 启动计费请求
                sys_time.sleep(1)
                self.start_charging_process()
            return

        # 计费帧处理
        if frame_type in [FRAME_TYPE_BILLING_REQUEST_REPLY, FRAME_TYPE_BILLING_SET]:
            reply_frame = self.builder.build_billing_set_reply()
            self.safe_send(reply_frame)
            #logger.info(f"已发送计费模型确认帧 (0x57): {reply_frame.hex()}")
            self.handle_billing_data(data)
            return

        # 尝试提取设备ID（枪号）
        try:
            # 解密数据获取设备ID
            frame_hex = data.hex()
            encrypted_flag = data[4]
            if encrypted_flag != 0x01:
                logger.debug("非加密帧，跳过处理")
                return

            encrypted_data = frame_hex[12:-4]  # 移除帧头和CRC
            decrypted_hex = self.guns["01"].aes_decrypt(encrypted_data)  # 使用任意枪的解密方法

            # 根据帧类型提取设备ID
            if frame_type == FRAME_TYPE_START_CHARGE:
                # 启动充电帧：使用切片获取设备ID
                device_id_hex = decrypted_hex[32:48]  # 协议固定位置
                gun_id = device_id_hex[-2:]  # 设备ID末两位为枪号
            elif frame_type == FRAME_TYPE_STOP_CHARGE:
                # 停止充电帧：直接使用完整解密字符串作为设备ID
                device_id_hex = decrypted_hex
                gun_id = device_id_hex[-2:]
            else:
                # 其他帧类型：保持原有处理方式
                #logger.info(f"接收到其他帧类型，跳过设备ID提取: {frame_type}")
                return

            logger.debug(f"提取的设备ID: {device_id_hex} | 枪号: {gun_id}")

            # 处理帧数据
            if gun_id in self.guns:
                gun = self.guns[gun_id]
                if frame_type == FRAME_TYPE_START_CHARGE:
                    self.handle_start_charge(data, gun)
                elif frame_type == FRAME_TYPE_STOP_CHARGE:
                    self.handle_stop_charge(data, gun)
                else:
                    logger.warning(f"未处理的帧类型: 0x{frame_type:02X}")
            else:
                logger.error(f"未知枪号: {gun_id}")
        except Exception as e:
            logger.error(f"数据处理错误: {e}")
            self.disconnect("数据处理错误")  # 添加停止原因

    def handle_billing_data(self, frame):
        """处理费率数据（全桩共享）"""
        #logger.info("处理费率数据")
        try:
            frame_hex = frame.hex()
            encrypted_data = frame_hex[12:-4]  # 移除帧头和CRC

            # 使用第一把枪处理费率数据
            gun = self.guns["01"]
            decrypted_hex = gun.aes_decrypt(encrypted_data)

            # 解析费率参数
            rate_peak = little_endian_hex_to_dec(decrypted_hex[18:26]) / 100000
            rate_peak_service = little_endian_hex_to_dec(decrypted_hex[26:34]) / 100000
            rate_standard = little_endian_hex_to_dec(decrypted_hex[34:42]) / 100000
            rate_standard_service = little_endian_hex_to_dec(decrypted_hex[42:50]) / 100000
            rate_off_peak = little_endian_hex_to_dec(decrypted_hex[50:58]) / 100000
            rate_off_peak_service = little_endian_hex_to_dec(decrypted_hex[58:66]) / 100000
            rate_valley = little_endian_hex_to_dec(decrypted_hex[66:74]) / 100000
            rate_valley_service = little_endian_hex_to_dec(decrypted_hex[74:82]) / 100000

            # 计算总费率
            rate_peak_all = decimal_to_little_endian_hex((rate_peak + rate_peak_service) * 100000)
            rate_standard_all = decimal_to_little_endian_hex((rate_standard + rate_standard_service) * 100000)
            rate_off_peak_all = decimal_to_little_endian_hex((rate_off_peak + rate_off_peak_service) * 100000)
            rate_valley_all = decimal_to_little_endian_hex((rate_valley + rate_valley_service) * 100000)

            # 构建费率映射
            RATE_MAPPING = {
                "00": {"energy": rate_peak, "service": rate_peak_service},
                "01": {"energy": rate_standard, "service": rate_standard_service},
                "02": {"energy": rate_off_peak, "service": rate_off_peak_service},
                "03": {"energy": rate_valley, "service": rate_valley_service}
            }

            # 解析费率时段
            RATE_PERIODS = []
            for i in range(48):  # 48个半小时段
                start_hour = i // 2
                start_min = 30 if i % 2 else 0
                end_hour = (start_hour + 1) if start_min == 30 else start_hour
                end_min = 0 if start_min == 30 else 30

                if i == 47:  # 最后一段
                    end_hour = 0
                    end_min = 0

                rate_type = decrypted_hex[84 + i * 2:86 + i * 2]
                RATE_PERIODS.append({
                    "start": time(start_hour, start_min),
                    "end": time(end_hour, end_min),
                    "rate_type": rate_type
                })

            # 更新所有枪的费率信息
            for gun in self.guns.values():
                gun.rate_peak = rate_peak
                gun.rate_peak_service = rate_peak_service
                gun.rate_standard = rate_standard
                gun.rate_standard_service = rate_standard_service
                gun.rate_off_peak = rate_off_peak
                gun.rate_off_peak_service = rate_off_peak_service
                gun.rate_valley = rate_valley
                gun.rate_valley_service = rate_valley_service
                gun.rate_peak_all = rate_peak_all
                gun.rate_standard_all = rate_standard_all
                gun.rate_off_peak_all = rate_off_peak_all
                gun.rate_valley_all = rate_valley_all
                gun.RATE_MAPPING = RATE_MAPPING
                gun.RATE_PERIODS = update_rates(RATE_MAPPING, RATE_PERIODS)

            logger.info(f"桩 {self.pile.number} 费率信息更新成功")
            #logger.info(f"费率信息更新成功")
            logger.debug(f"时段费率表：{RATE_PERIODS}")
        except Exception as e:
            logger.error(f"费率解析错误: {e}")

    def handle_start_charge(self, frame, gun):
        """启动充电（枪级）"""
        try:
            frame_hex = frame.hex()
            encrypted_data = frame_hex[12:-4]  # 移除帧头和CRC
            decrypted = gun.aes_decrypt(encrypted_data)
            order_sn = decrypted[:32]  # 协议前32位为订单号

            # 启动充电
            gun.start_charging(order_sn)

            # 发送响应帧
            self.safe_send(self.builder.build_start_reply(order_sn, gun.device_id))
            self.safe_send(self.builder.build_charge_handshake(order_sn, gun.device_id))

            # 启动数据上报线程
            threading.Thread(target=self.data_reporting, args=(gun,), daemon=True).start()
            #logger.info(f"枪 {gun.gun_id} 启动充电 | 订单: {order_sn}")
        except Exception as e:
            logger.error(f"启动充电错误: {e}")
            self.disconnect("启动充电错误")  # 添加停止原因

    def data_reporting(self, gun):
        """枪级数据上报"""
        try:
            #logger.info(f"枪 {gun.gun_id} 数据上报线程启动")
            while gun.charging and self.running:
                # 获取充电数据
                result = gun.get_charging_data()
                if result is None:
                    break
                bat_soc, cha_time, bat_over_cha_time, cha_ene_hex, ChaMoney = result
                # 发送各种数据帧
                self.safe_send(self.builder.build_bms_data(gun.current_order, gun.device_id))
                self.safe_send(self.builder.build_realtime_data(
                    gun.current_order, gun.device_id,
                    bat_soc, cha_time, bat_over_cha_time,
                    cha_ene_hex, ChaMoney))
                self.safe_send(self.builder.build_odp_data(
                    gun.current_order, gun.device_id,
                    bat_soc, bat_over_cha_time, cha_time))
                sys_time.sleep(15)  # 15秒上报间隔
            logger.info(f"枪 {gun.gun_id} 数据上报线程退出")
        except Exception as e:
            logger.error(f"枪 {gun.gun_id} 上报异常: {e}")
            self.disconnect(f"枪 {gun.gun_id} 上报异常")  # 添加停止原因

    def handle_stop_charge(self, frame, gun):
        """停止充电（枪级）"""
        try:
            gun.stop_charging('充电完成')
            self.safe_send(self.builder.build_stop_reply(gun.device_id))
            self.safe_send(self.builder.build_stop_pile(
                gun.current_order, gun.device_id,
                gun.last_bat_soc, gun.last_cha_time, gun.last_cha_ene
            ))

            # 准备交易记录数据
            energy_00 = int(gun.rate_energy_sums.get("00", 0.0) * 10000)
            energy_01 = int(gun.rate_energy_sums.get("01", 0.0) * 10000)
            energy_02 = int(gun.rate_energy_sums.get("02", 0.0) * 10000)
            energy_03 = int(gun.rate_energy_sums.get("03", 0.0) * 10000)

            cost_00 = int(gun.rate_total_cost_sums.get("00", 0.0) * 10000)
            cost_01 = int(gun.rate_total_cost_sums.get("01", 0.0) * 10000)
            cost_02 = int(gun.rate_total_cost_sums.get("02", 0.0) * 10000)
            cost_03 = int(gun.rate_total_cost_sums.get("03", 0.0) * 10000)

            energy_00_hex = decimal_to_little_endian_hex(energy_00).zfill(8)
            cost_00_hex = decimal_to_little_endian_hex(cost_00).zfill(8)
            energy_01_hex = decimal_to_little_endian_hex(energy_01).zfill(8)
            cost_01_hex = decimal_to_little_endian_hex(cost_01).zfill(8)
            energy_02_hex = decimal_to_little_endian_hex(energy_02).zfill(8)
            cost_02_hex = decimal_to_little_endian_hex(cost_02).zfill(8)
            energy_03_hex = decimal_to_little_endian_hex(energy_03).zfill(8)
            cost_03_hex = decimal_to_little_endian_hex(cost_03).zfill(8)

            # 发送交易记录
            self.safe_send(self.builder.build_transaction_record(
                gun.current_order, gun.device_id,
                gun.stop_charge_time, gun.start_charge_time,
                gun.rate_peak_all, gun.rate_standard_all,
                gun.rate_off_peak_all, gun.rate_valley_all,
                energy_00_hex, cost_00_hex, energy_01_hex, cost_01_hex,
                energy_02_hex, cost_02_hex, energy_03_hex, cost_03_hex,
                gun.cha_ene_end, gun.last_cha_ene, gun.last_ChaMoney
            ))
            #logger.info(f"枪 {gun.gun_id} 停止充电处理完成")
        except Exception as e:
            logger.error(f"停止异常: {e}")
            self.disconnect("停止充电错误")  # 添加停止原因

    def start_charging_process(self):
        """启动充电流程"""
        try:
            self.safe_send(self.builder.build_billing_request())
            #logger.info(f"桩 {self.pile.number} 发送计费请求")
        except Exception as e:
            logger.error(f"启动充电流程失败: {e}")
            self.disconnect("启动充电流程失败")  # 添加停止原因
    def heartbeat_loop(self):
        """心跳维持（全枪）"""
        logger.info(f"桩 {self.pile.number} 心跳线程启动")
        while self.running:
            try:
                for gun_id, gun in self.guns.items():
                    self.safe_send(self.builder.build_heartbeat(gun.device_id))
                    if not gun.charging:  # 仅未充电枪发送待机数据
                        self.safe_send(self.builder.build_standby_data(
                            gun.device_id, gun.pile_sta, gun.pile_on))
                sys_time.sleep(10)
            except Exception as e:
                if self.running:
                    logger.error(f"心跳异常: {e}")
                    self.disconnect("心跳异常")  # 添加停止原因
                break
        logger.info(f"桩 {self.pile.number} 心跳线程退出")

# 全局连接管理器
pile_connections = {}
def connect_pile(pile_id):
    try:
        pile = Pile.objects.get(pk=pile_id)

        # 如果已连接但状态不一致，先断开
        if pile_id in pile_connections:
            if pile.logged_in:
                logger.info(f"桩 {pile.number} 已连接，状态一致")
                return True
            else:
                disconnect_pile(pile_id)

        # 创建连接器
        connector = PileConnector(pile)
        if connector.connect():
            pile_connections[pile_id] = connector

            # 强制更新数据库状态
            pile.logged_in = True
            pile.save(update_fields=['logged_in'])
            threading.Thread(target=connector.heartbeat_loop, daemon=True).start()
            return True

        # 连接失败，确保状态更新
        pile.logged_in = False
        pile.save(update_fields=['logged_in'])
        return False
    except Pile.DoesNotExist:
        logger.error(f"找不到桩 {pile_id}")
        return False
    except Exception as e:
        logger.error(f"连接桩 {pile_id} 失败: {e}")
        return False

def disconnect_pile(pile_id, stop_reason="正常断开"):
    if pile_id in pile_connections:
        connector = pile_connections.pop(pile_id)
        connector.disconnect(stop_reason)
        return True
    # 如果不在连接池中，但数据库状态显示已登录
    try:
        pile = Pile.objects.get(pk=pile_id)
        if pile.logged_in:
            logger.warning(f"桩 {pile.number} 不在连接池中，但数据库状态为已登录，强制更新")
            pile.logged_in = False
            pile.save(update_fields=['logged_in'])
        return True
    except Pile.DoesNotExist:
        return False

def start_charging(pile_id):
    if pile_id in pile_connections:
        connector = pile_connections[pile_id]
        connector.start_charging_process()
        return True
    logger.warning(f"桩 {pile_id} 未连接，无法启动充电")
    return False